{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modFileVerif;

interface

uses Classes, SysUtils, modMd5, modInteractionAuteur;

type
    TFichierTextSignature = class(TObject)
    private
       FContenuFichier: string;
       FUnixDate: int64;


       function GetStream: TStream;

    public
       property FichierContenu: string read FContenuFichier;
       property FichierStream : TStream read GetStream;
       property FichierDateGen: int64 read FUnixDate;


       function LoadAndCheck(Fichier: string; PublicKeyFile: TStream): boolean;

       constructor Create;
       destructor Destroy; override;

    end;

 {$IFDEF VERADMIN}
  function  mfvSigneFichier(Fichier: string; PrivateKeyFile: string; DateUnixInt64: int64): boolean;
 {$ENDIF}


implementation

{$IFDEF VERADMIN}
uses modInteractionAuthAdmin;
{$ENDIF}

constructor TFichierTextSignature.Create;
begin
    inherited Create;


end;

destructor TFichierTextSignature.Destroy;
begin


    inherited Destroy;
end;

function TFichierTextSignature.GetStream: TStream;
var s: TMemoryStream;
begin

    if length(FContenuFichier) < 5 then begin
       Result := nil;
       exit;
    end;

    s := TMemoryStream.Create;
    s.Write(FContenuFichier[1], length(FContenuFichier));

    s.Seek(0, soBeginning);

    Result := s;

end;


function TFichierTextSignature.LoadAndCheck(Fichier: string; PublicKeyFile: TStream): boolean;
var Stream: TFileStream;

    md5ori, md5current: string;

    FIn: TextFile;
    Ligne, BufferCrypted, BufferDeCrypted: string;
    b_in_crypted: boolean;
    Taille: integer;
    xPos: integer;
    sFileName: string;
begin
    Result := false;

    FUnixDate := 0;

    if FileExists(Fichier) = false then begin
       exit;
    end;

    AssignFile(FIn, Fichier);

    {$I-}
    ReSet(FIn);
    {$I+}

    if IOResult <> 0 then begin
       // erreur
       exit;
    end;



    b_in_crypted := false;
    FContenuFichier := '';

    while Not(EoF(FIn)) do begin
       ReadLn(FIn, Ligne);

       if b_in_crypted = false then begin
          if pos('------------------------', Ligne) > 0 then begin
             b_in_crypted := true;
             BufferCrypted := '';
          end else begin
             FContenuFichier := FContenuFichier + Ligne + #$0D#$0A;
          end;

       end else begin
          if pos('------------------------', Ligne) > 0 then begin
             b_in_crypted := false;

          end else begin
             BufferCrypted := BufferCrypted + Ligne;
          end;

       end;

    end;

    CloseFile(FIn);

    if length(BufferCrypted) < 10 then begin
       // fichier invalide
       FContenuFichier := '';
       exit;
    end;

    BufferCrypted := iaRemoveChunk(BufferCrypted);

    BufferDeCrypted := iaRSADecryptageKeyStream(BufferCrypted, PublicKeyFile, CNT_PUBLICKEY_PASSPHRASE);


    ///////////////////////////////////
    ///   MD5
    ///////////////////////////////////

    xPos := pos(',', BufferDeCrypted);

    if (xPos < 5) then begin
       // erreur...
       FContenuFichier := '';
       exit;
    end;

    md5ori := copy(BufferDeCrypted, 1, xPos - 1);
    System.Delete(BufferDeCrypted, 1, xPos);

    if length(md5ori) <> 32 then begin
       // Erreur
       FContenuFichier := '';
       exit;
    end;



    ///////////////////////////////////
    ///   Taille
    ///////////////////////////////////

    xPos := pos(',', BufferDeCrypted);
    if xPos < 2 then begin
       // erreur
       FContenuFichier := '';
       exit;
    end;


    Taille := StrToIntDef(copy(BufferDeCrypted, 1, xPos - 1), -1);

    if (Taille < 4) then begin
       // erreur
       FContenuFichier := '';
       exit;
    end;

    System.Delete(BufferDeCrypted, 1, xPos);




    ///////////////////////////////////
    ///   Date unix
    ///////////////////////////////////

    xPos := pos(',', BufferDeCrypted);
    if xPos > 0 then begin
       // Version plus recente ?
       System.Delete(BufferDeCrypted, xPos, maxint);
    end;

    FUnixDate := StrToInt64Def(BufferDeCrypted, 0);

    if FUnixDate < 500 then begin
       // erreur
       FUnixDate := 0;
       FContenuFichier := '';
       exit;
    end;



    

    try
       Stream := TFileStream.Create(Fichier, fmOpenRead);
    except
       Stream := nil;
    end;

    if Stream = nil then begin
       FContenuFichier := '';
       exit;
    end;

    if Stream.Size < Taille then begin
       // erreur...
       Stream.Free;
       FContenuFichier := '';
       exit;
    end;

    md5current := md5ArrayToStr(md5Stream(Stream, Taille));


    Stream.Free;

    // puis on ajoute le nom du fichier
    sFileName := lowercase(ExtractFileName(Fichier));
    md5current := md5StringX(md5current + sFileName);


    // compare les md5
    if (SameText(md5current, md5ori) = true)  then begin
       // ils sont egaux
       Result := true;



    end else begin
       // ils ne sont pas egaux
       FContenuFichier := '';
       exit;
    end;

    
end;



{$IFDEF VERADMIN}
function mfvSigneFichier(Fichier: string; PrivateKeyFile: string; DateUnixInt64: int64): boolean;
var Stream: TFileStream;
    md5: TMd5HashInfo;
    FOut: TextFile;
    Taille: int64;

    md5str: string;

    sDataIn: string;
    sFinalData: string;
    sFileName: string;
begin

    Result := false;


    try
       Stream := TFileStream.Create(Fichier, fmOpenRead);
    except
       Stream := nil;
    end;

    if Stream = nil then begin
       exit;
    end;

    Taille := Stream.Size;

    if (Taille < 4) then begin
       Stream.Free;
       exit;
    end;

    Taille := Taille - 2;

    md5 := md5Stream(Stream, Taille);

    Stream.Free;

    sFileName := lowercase(ExtractFileName(Fichier));


    // Puis on ajoute le nom du fichier
    md5str := md5StringX(md5ArrayToStr(md5) + sFileName);


    
    sDataIn := md5str + ',' + IntToStr(Taille) + ',' + IntToStr(DateUnixInt64);


    sFinalData := iaRSACryptageChaine(sDataIn, PrivateKeyFile, CNT_PRIVATEKEY_PASSPHRASE);


    AssignFile(FOut, Fichier);

    {$I-}
    Append(FOut);
    {$I+}

    if IOResult <> 0 then begin
       // erreur
       exit;
    end;




    WriteLn(FOut, '');
    WriteLn(FOut, '--------------------------');

    sFinalData := trim(iaCreateChunkOf64Char(sFinalData));
    WriteLn(FOut, sFinalData);

    
    WriteLn(FOut, '--------------------------');
    WriteLn(FOut, '');
    
    CloseFile(FOut);

    Result := true;
    

end;
{$ENDIF}



end.
